/*
 * Copyright 2016 Stuart Kent
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package com.example.mybugshaker.flow.email;

import com.example.mybugshaker.ActivityReferenceManager;
import com.example.mybugshaker.BugShaker;
import com.example.mybugshaker.flow.dialog.DialogProvider;
import com.example.mybugshaker.flow.email.screenshot.ScreenshotProvider;
import com.example.mybugshaker.utils.AbilityUtils;
import com.example.mybugshaker.utils.Logger;
import com.example.mybugshaker.utils.Toaster;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.window.dialog.IDialog;
import ohos.agp.window.dialog.ToastDialog;
import ohos.agp.window.service.WindowManager;
import ohos.app.Context;
import ohos.bundle.AbilityInfo;
import ohos.bundle.IBundleManager;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.rpc.RemoteException;
import ohos.utils.net.Uri;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.List;


public class FeedbackEmailFlowManager {
    private static final int FLAG_SECURE_VALUE = 0x00002000;

    @NotNull
    private final Context applicationContext;

    @NotNull
    private final Toaster toaster;

    @NotNull
    private final ActivityReferenceManager activityReferenceManager;

    @NotNull
    private final EmailCapabilitiesProvider emailCapabilitiesProvider;

    public final FeedbackEmailIntentProvider getFeedbackEmailIntentProvider() {
        return feedbackEmailIntentProvider;
    }

    @NotNull
    private final FeedbackEmailIntentProvider feedbackEmailIntentProvider;

    @NotNull
    private final ScreenshotProvider screenshotProvider;

    @NotNull
    private final DialogProvider alertDialogProvider;

    @NotNull
    private final Logger logger;

    @Nullable
    private ToastDialog alertDialog;

    private String[] emailAddresses;
    private String emailSubjectLine;
    private boolean ignoreFlagSecure;
    private final HiLogLabel lable = new HiLogLabel(HiLog.LOG_APP, 0x00201, "FeedbackEmailFlowManager");

    private final IDialog.ClickedListener reportBugClickListener = new IDialog.ClickedListener() {
        @Override
        public void onClick(final IDialog dialog, final int which) {
            setOnClick();
        }
    };

    private void setOnClick(){
        final Ability ability = activityReferenceManager.getValidatedActivity();
        if (ability == null) {
            return;
        }
        // Todo 发邮件
        if (shouldAttemptToCaptureScreenshot(ability)) {
            try {
                if (emailCapabilitiesProvider.canSendEmailsWithAttachments()) {
                    screenshotProvider.getScreenshotUri(ability)
                            .observeOn(HmOSSchedulers.mainThread())
                            .subscribeOn(HmOSSchedulers.mainThread())
                            .subscribe(new Observer<Uri>() {
                                @Override
                                public void onSubscribe(@NotNull Disposable disposable) { }
                                @Override
                                public void onNext(@NotNull Uri uri) {
                                    sendEmailWithScreenshot(ability, uri);
                                }
                                @Override
                                public void onError(@NotNull Throwable throwable) {
                                    final String errorString = "Screenshot capture failed";
                                    toaster.toast(errorString);
                                    logger.e(errorString);
                                    logger.printStackTrace(throwable);
                                    sendEmailWithoutScreenshot(ability);
                                }
                                @Override
                                public void onComplete() {
                                    // This method intentionally left blank.
                                }
                            });
                } else {
                    sendEmailWithoutScreenshot(ability);
                }
            } catch (RemoteException e) {
                HiLog.error(lable,"FeedbackEmailFlowManager", e);
            }
        } else {
            final String warningString = "Window is secured; no screenshot taken";

            toaster.toast(warningString);
            logger.d(warningString);

            sendEmailWithoutScreenshot(ability);
        }
    }

    @SuppressWarnings("ParameterNumber")
    public FeedbackEmailFlowManager(
            @NotNull final Context context,
            @NotNull final EmailCapabilitiesProvider femailCapabilitiesProvider,
            @NotNull final Toaster ftoaster,
            @NotNull final ActivityReferenceManager factivityReferenceManager,
            @NotNull final FeedbackEmailIntentProvider ffeedbackEmailIntentProvider,
            @NotNull final ScreenshotProvider fscreenshotProvider,
            @NotNull final DialogProvider dialogProvider,
            @NotNull final Logger flogger) {

        this.applicationContext = context;
        this.emailCapabilitiesProvider = femailCapabilitiesProvider;
        this.toaster = ftoaster;
        this.activityReferenceManager = factivityReferenceManager;
        this.feedbackEmailIntentProvider = ffeedbackEmailIntentProvider;
        this.screenshotProvider = fscreenshotProvider;
        this.alertDialogProvider = dialogProvider;
        this.logger = flogger;
    }

    public final void onActivityResumed(@NotNull final Ability ability) {
        dismissDialog();
        activityReferenceManager.setActivity(ability);
    }

    public final void onActivityStopped() {
        dismissDialog();
    }

    public final void startFlowIfNeeded(
            @NotNull final String[] femailAddresses,
            @Nullable final String femailSubjectLine,
            final boolean fignoreFlagSecure) {
        if (isFeedbackFlowStarted()) {
            logger.d("Feedback flow already started; ignoring shake.");
            return;
        }

        this.emailAddresses = Arrays.copyOf(femailAddresses, femailAddresses.length);
        this.emailSubjectLine = femailSubjectLine;
        this.ignoreFlagSecure = fignoreFlagSecure;
        BugShaker.get(null).showDialog();
    }

    private boolean isFeedbackFlowStarted() {
        return alertDialog != null && alertDialog.isShowing();
    }

    private void showDialog() {
        final Ability currentActivity = activityReferenceManager.getValidatedActivity();
        if (currentActivity == null) {
            return;
        }
        alertDialog = alertDialogProvider.getAlertDialog(currentActivity, reportBugClickListener);
        alertDialog.show();
    }

    private void dismissDialog() {
        if (alertDialog != null) {
            alertDialog.setSwipeToDismiss(false);
            alertDialog = null;
        }
    }

    private boolean shouldAttemptToCaptureScreenshot(@NotNull final Ability ability) {
        final int windowFlags = AbilityUtils.getWindow(ability).getLayoutConfig().get().flags;

        final boolean isWindowSecured =
                (windowFlags & WindowManager.LayoutConfig.ALTER_FLAGS) == FLAG_SECURE_VALUE;

        final boolean result = ignoreFlagSecure || !isWindowSecured;

        if (!isWindowSecured) {
            logger.d("Window is not secured; should attempt to capture screenshot.");
        } else {
            if (ignoreFlagSecure) {
                logger.d("Window is secured, but we're ignoring that.");
            } else {
                logger.d("Window is secured, and we're respecting that.");
            }
        }

        return result;
    }

    public final void sendEmailWithScreenshot(
            @NotNull final Ability ability,
            @NotNull final Uri screenshotUri) {

        final Intent feedbackEmailIntent = feedbackEmailIntentProvider.getFeedbackEmailIntent(
                emailAddresses,
                emailSubjectLine,
                screenshotUri);

        final List<AbilityInfo> resolveInfoList;
        try {
            resolveInfoList = applicationContext.getBundleManager()
                    .queryAbilityByIntent(feedbackEmailIntent, IBundleManager.SIGNATURE_MATCHED, IBundleManager.SIGNATURE_MATCHED);
            for (final AbilityInfo receivingApplicationInfo : resolveInfoList) {
                // FIXME: revoke these permissions at some point!
                applicationContext.compelVerifyUriPermission(
                        screenshotUri,
                        Intent.FLAG_ABILITY_CLEAR_MISSION,
                        receivingApplicationInfo.getApplicationInfo().name);
            }
            ability.startAbility(feedbackEmailIntent);

        } catch (RemoteException e) {
            HiLog.error(lable,"FeedbackEmailFlowManager", e);
        }

        logger.d("Sending email with screenshot.");
    }

    private void sendEmailWithoutScreenshot(@NotNull final Ability ability) {
        final Intent feedbackEmailIntent = feedbackEmailIntentProvider.getFeedbackEmailIntent(
                emailAddresses,
                emailSubjectLine);
        ability.startAbility(feedbackEmailIntent);

        logger.d("Sending email with no screenshot.");
    }
}
